import java.net.DatagramPacket;
import java.net.InetAddress;

import org.forum.jstun.StunAttribute;
import org.forum.jstun.StunMessage;
import org.forum.jstun.NatDetector;
import org.forum.jstun.PeriodDetector;
import org.forum.jstun.StunClient;

// for test stun
public class Test {
	private InetAddress mMappedAddress;
	private int mMappedPort;

	public void testStun(String server, int port) {
		StunClient stun = new StunClient(server, port);
		stun.setSendListener(new StunClient.SendListener(){
			@Override
			public StunMessage onSend(StunMessage msg) {
				System.out.println("send msg "+msg.getLength());
				if (msg.getType()!=StunMessage.TYPE_BINDING_REQUEST) return msg;
				// TR111 Connection Request Binding
				msg.appendAttribute(new StunAttribute((short)0xc001, 
						"dslforum.org/TR-111 ".getBytes()));
				// TR111 Binding Change
				msg.appendAttribute(new StunAttribute((short)0xc002));
				return msg;
			}
		});

		stun.setStunParser(new StunClient.StunParser() {
			@Override
			public StunMessage parse(DatagramPacket packet) {
				System.out.println("receive packet: "+packet);
				if (mMappedAddress!=null) {
					String httpget = "GET http://"+mMappedAddress.getHostAddress()+":"+mMappedPort;
					String httpline = new String(packet.getData());
					if (httpline!=null && httpline.startsWith(httpget)) {
						// TR111 UDP Connection Request
						System.out.println("TR111 UDP Connection Request: "+httpline);
						return null;	// ignore this message
					}
				}
				// use default parser
				StunMessage msg = StunMessage.parse(packet.getData(), packet.getLength());
				if (msg!=null) {
					StunAttribute ma = msg.getAttribute(StunAttribute.TYPE_MAPPED_ADDRESS);
					mMappedAddress = ((StunMessage.StunAddress)ma).getAddress();
					mMappedPort = ((StunMessage.StunAddress)ma).getPort();
					System.out.println("Mapped "+mMappedAddress.getHostAddress()+":"+mMappedPort);
				}
				return msg;
			}
		});

		new Thread(stun).start();
	}

	public void testNatDetector(String server, int port) {
		final NatDetector detector = new NatDetector(server, port);
		detector.setDetectListener(new NatDetector.DetectListener(){
			@Override
			public void onFinish(int state) {
				System.out.println("state="+state+" nat type="+detector.getNatType());
			}
		});
		new Thread(detector).start();
	}

	public void testPeroidDetector(String server, int port) {
		final PeriodDetector detector = new PeriodDetector(server, port);
		detector.setBoundListener(new PeriodDetector.BoundListener(){
			@Override
			public void onUpdate(long min, long max) {
				System.out.println("current bound ["+min+", "+max+")");
				if (max>1000*60*5) {
					System.out.println("bound out of range, stop");
					detector.stop();
				}
			}
		});
		detector.setPeriodListener(new PeriodDetector.PeriodListener(){
			@Override
			public void onFinish(long period) {
				System.out.println("detect period interval "+period);
			}
		});
		new Thread(detector).start();
	}

	public static void main(String[] args) {
		String server = "stun.schlund.de";
		int port = 3478;
		System.out.println("stun server="+server+" port="+port);
		Test test = new Test();
		//test.testPeroidDetector(server, port);
		//test.testNatDetector(server, port);
		test.testStun(server, port);
	}
}